package com.annimon.stream;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.*;
import org.junit.Test;
/**
* Standard list/set/map iterator checks write count, so adding data to list
* after creating Stream can throw ConcurrentModificationException.
*/
public class IteratorIssueTest {
@Test(expected = ConcurrentModificationException.class)
public void testArrayListIterator() {
final int count = 5;
final List<Integer> data = new ArrayList<Integer>();
for (int i = 0; i < count; i++) {
data.add(i);
}
Stream stream = Stream.of(data.iterator())
.filter(Functions.remainder(2));
for (int i = 0; i < count; i++) {
data.add(count + i);
}
assertEquals(count, stream.count());
}
@Test
public void testArrayListIteratorFix() {
final int count = 5;
final List<Integer> data = new ArrayList<Integer>(count);
for (int i = 0; i < count; i++) {
data.add(i);
}
Stream stream = Stream.of(new CustomIterator<Integer>(data))
.filter(Functions.remainder(2));
for (int i = 0; i < count; i++) {
data.add(count + i);
}
assertEquals(count, stream.count());
}
@Test
public void testHashSetIterator() {
final int count = 5;
final Set<Integer> data = new HashSet<Integer>();
for (int i = 0; i < count; i++) {
data.add(i);
}
Stream stream = Stream.of(data)
.filter(Functions.remainder(2));
for (int i = 0; i < count; i++) {
data.add(count + i);
}
assertEquals(count, stream.count());
}
static class CustomIterator<T> implements Iterator<T> {
private final List<T> list;
private int index;
public CustomIterator(List<T> list) {
this.list = list;
index = 0;
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public T next() {
return list.get(index++);
}
@Override
public void remove() {
throw new UnsupportedOperationException("remove not supported");
}
}
}